package com.zkyt.lib_msdk_ext.component

import android.graphics.Point
import android.util.Log
import androidx.annotation.IntRange
import com.geoai.mavlink.geoainet.base.mavlinkcore.engine.GEOAIError
import com.geoai.mavlink.geoainet.base.mavlinkcore.interfaces.CompletionCallback
import com.geoai.mavlink.geoainet.flycontroller.enums.AircraftFailSafeBehaviorMode
import com.geoai.mavlink.geoainet.flycontroller.enums.AircraftPrecisionLandMode
import com.geoai.mavlink.geoainet.flycontroller.enums.AircraftReturnMode
import com.geoai.mavlink.geoainet.flycontroller.info.AircraftDiagnosticsStateInfo
import com.geoai.mavlink.geoainet.flycontroller.info.CompassCalibrationStateInfo
import com.geoai.mavlink.geoainet.flycontroller.info.FlyControllerStateInfo
import com.geoai.mavlink.geoainet.flycontroller.info.ParachuteStateInfo
import com.geoai.mavlink.geoainet.flycontroller.interfaces.IBaseFlyControllerManager
import com.zkyt.lib_msdk_ext.common.CallbackWithRxHandler
import com.zkyt.lib_msdk_ext.common.CompletionCbRxHandler
import com.zkyt.lib_msdk_ext.common.SDKExceptionWrapper
import com.zkyt.lib_msdk_ext.common.SDKExtUtil
import com.zkyt.lib_msdk_ext.common.SDKExtUtil.handleError
import com.zkyt.lib_msdk_ext.log.SDKExtLog
import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.subjects.BehaviorSubject
import java.util.Optional

/**
 * Created by chenyu on 2024/1/10
 * Description:
 */
object FlyControllerManagerExt: AbsSDKExt<IBaseFlyControllerManager>() {
    private var flyControllerManager: IBaseFlyControllerManager? = null

    private var originFlyControllerStateObservable =
        BehaviorSubject.createDefault< Optional<FlyControllerStateInfo>>(Optional.ofNullable(null))
    private var originFlyControllerParachuteStateObservable =
        BehaviorSubject.createDefault< Optional<ParachuteStateInfo>>(Optional.ofNullable(null))
    private var originDiagnosticsStateObservable =
        BehaviorSubject.createDefault<Optional<List<AircraftDiagnosticsStateInfo>>>(
            Optional.ofNullable(
                null
            )
        )
    private var originCompassCalibrationStateObservable =
        BehaviorSubject.createDefault<Optional<CompassCalibrationStateInfo>>(
            Optional.ofNullable(
                null
            )
        )

    override fun init(originManager: IBaseFlyControllerManager) {
        this.flyControllerManager = originManager

        this.flyControllerManager?.setFlyControllerStateListener { info ->
            originFlyControllerStateObservable.onNext(Optional.of(info))
        }
        this.flyControllerManager?.setParachuteStateListener { info ->
            originFlyControllerParachuteStateObservable.onNext(Optional.of(info))
        }
        this.flyControllerManager?.setDiagnosticsStateListener { info ->
            originDiagnosticsStateObservable.onNext(Optional.of(info))
        }

        this.flyControllerManager?.setCalibrationCompassListener { info ->
            originCompassCalibrationStateObservable.onNext(Optional.of(info))
        }

    }

    override fun destroy() {
        super.destroy()
        flyControllerManager?.setFlyControllerStateListener(null)
        flyControllerManager?.setDiagnosticsStateListener(null)
        flyControllerManager?.setCalibrationCompassListener(null)
        originFlyControllerStateObservable.onNext(Optional.ofNullable(null))
        originDiagnosticsStateObservable.onNext(Optional.ofNullable(null))
        originCompassCalibrationStateObservable.onNext(Optional.ofNullable(null))

        flyControllerManager = null
    }

    override fun getOriginManager(): IBaseFlyControllerManager? {
        return flyControllerManager
    }

    fun getFlyControllerStateObservable(): Observable<Optional<FlyControllerStateInfo>> {
        return originFlyControllerStateObservable.hide()
    }

    fun getFlyControllerParachuteStateObservable(): Observable<Optional<ParachuteStateInfo>> {
        return originFlyControllerParachuteStateObservable.hide()
    }

    fun getDiagnosticsStateObservable(): Observable<Optional<List<AircraftDiagnosticsStateInfo>>> {
        return originDiagnosticsStateObservable.hide()
    }

    fun getCompassCalibrationStateObservable(): Observable<Optional<CompassCalibrationStateInfo>> {
        return originCompassCalibrationStateObservable.hide()
    }

    fun startAircraftTakeoffRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.startAircraftTakeoff {
                handleError(emitter, it)
            }
        }
    }

    fun stopAircraftGoHomeRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.stopAircraftGoHome {
                handleError(emitter, it)
            }
        }
    }

    fun startAircraftLandRx(isPrecise: Boolean): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.startAircraftLand(isPrecise) {
                handleError(emitter, it)
            }
        }
    }

    fun stopAircraftLandRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.stopAircraftLand {
                handleError(emitter, it)
            }
        }
    }

    fun startAircraftGoHomeRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.startAircraftGoHome {
                handleError(emitter, it)
            }
        }
    }

    fun startAircraftReturnRx(type: AircraftReturnMode): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.startAircraftReturn(type) {
                handleError(emitter, it)
            }
        }
    }

    fun startAircraftReturnAssignRallyRx(index: Int): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.startAircraftReturnAssignRally(index) {
                handleError(emitter, it)
            }
        }
    }

    fun setGoHomeAltitudeRx(altitude: Int): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setGoHomeAltitude(altitude) {
                handleError(emitter, it)
            }
        }
    }

    fun getGoHomeAltitudeRx(): Single<Int> {
        return Single.create { emitter ->
            flyControllerManager?.getGoHomeAltitude(CallbackWithRxHandler(emitter))
        }
    }

    fun getGoHomeAltitudeObservable(): Observable<Optional<Int>> {
        val curMethod = object : Any() {}.javaClass.enclosingMethod
        return autoGetProcessor.getAutoGetSubject(curMethod, this::getGoHomeAltitudeRx, 2000)
    }

    fun getGoHomeLocationRx(): Single<DoubleArray> {
        return Single.create { emitter ->
            flyControllerManager?.getGoHomeLocation(CallbackWithRxHandler(emitter))
        }
    }

    fun getGoHomeLocationObservable(): Observable<Optional<DoubleArray>> {
        val curMethod = object : Any() {}.javaClass.enclosingMethod
        return autoGetProcessor.getAutoGetSubject(curMethod, this::getGoHomeLocationRx, 1000)
    }


    fun stopAllActionRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.stopAllAction {
                handleError(emitter, it)
            }
        }
    }

    fun startForceLandingRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.startForceLanding {
                handleError(emitter, it)
            }
        }
    }

    fun setDroneArmRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setDroneArm {
                handleError(emitter, it)
            }

        }
    }

    fun setDroneDisarmRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setDroneDisarm {
                handleError(emitter, it)
            }

        }
    }

    fun setJoyStickEnableRx(enable: Boolean): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setJoyStickEnable(enable) {
                handleError(emitter, it)
            }

        }
    }

    fun sendJoyStickControlRx(
        x_axis: Short,
        y_axis: Short,
        z_axis: Short,
        r_axis: Short
    ): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.sendJoyStickControl(
                x_axis, y_axis, z_axis, r_axis
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun getAlternateLandingPointsRx(): Single<Array<Point>> {
        return Single.create { emitter ->
            flyControllerManager?.getAlternateLandingPoints(object :
                CompletionCallback.ICompletionCallbackWith<Array<Point>> {
                override fun onFailure(geoaiError: GEOAIError) {
                    emitter.onError(SDKExceptionWrapper(geoaiError))
                }

                override fun onResult(t: Array<Point>) {
                    emitter.onSuccess(t)
                }
            })
        }
    }

    fun setAlternateLandingPointsRx(points: Array<Point>): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setAlternateLandingPoints(
                points
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun setFcAltitudeLimitRx(@IntRange(from = 0, to = 500) limit: Int): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setFcAltitudeLimit(
                limit
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun getFcAltitudeLimitRx(): Single<Int> {
        return Single.create { emitter ->
            flyControllerManager?.getFcAltitudeLimit(CallbackWithRxHandler(emitter))
        }
    }

    fun getFcAltitudeLimitObservable(): Observable<Optional<Int>> {
        val curMethod = object : Any() {}.javaClass.enclosingMethod
        return autoGetProcessor.getAutoGetSubject(curMethod, this::getFcAltitudeLimitRx, 2000)
            .distinctUntilChanged()
    }

    fun setFcDistanceLimitRx(limit: Int): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setFcDistanceLimit(
                limit
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun getFcDistanceLimitRx(): Single<Int> {
        return Single.create { emitter ->
            flyControllerManager?.getFcDistanceLimit(CallbackWithRxHandler(emitter))
        }
    }

    fun getFcDistanceLimitObservable(): Observable<Optional<Int>> {
        val curMethod = object : Any() {}.javaClass.enclosingMethod
        return autoGetProcessor.getAutoGetSubject(curMethod, this::getFcDistanceLimitRx, 2000)
            .distinctUntilChanged()
    }

    fun setSimulateModeRx(enable: Boolean): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setSimulateMode(
                enable
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun getSimulateModeEnableRx(): Single<Boolean> {
        return Single.create { emitter ->
            flyControllerManager?.getSimulateModeEnable(CallbackWithRxHandler(emitter))
        }
    }

    fun setHorizonSpeedLimitRx(limit: Int): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setHorizonSpeedLimit(
                limit
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun getHorizonSpeedLimitRx(): Single<Float> {
        return Single.create { emitter ->
            flyControllerManager?.getHorizonSpeedLimit(CallbackWithRxHandler(emitter))
        }
    }

    fun getHorizonSpeedLimitObservable(): Observable<Optional<Float>> {
        val curMethod = object : Any() {}.javaClass.enclosingMethod
        return autoGetProcessor.getAutoGetSubject(curMethod, this::getHorizonSpeedLimitRx, 2000)
            .distinctUntilChanged()
    }

    fun getVerticalUpSpeedLimitRx(): Single<Float> {
        return Single.create { emitter ->
            flyControllerManager?.getVerticalUpSpeedLimit(CallbackWithRxHandler(emitter))
        }
    }

    fun getVerticalUpSpeedLimitObservable(): Observable<Optional<Float>> {
        val curMethod = object : Any() {}.javaClass.enclosingMethod
        return autoGetProcessor.getAutoGetSubject(curMethod, this::getVerticalUpSpeedLimitRx, 2000)
            .distinctUntilChanged()
    }

    fun getVerticalDownSpeedLimitRx(): Single<Float> {
        return Single.create { emitter ->
            flyControllerManager?.getVerticalUpSpeedLimit(CallbackWithRxHandler(emitter))
        }
    }

    fun getVerticalDownSpeedLimitObservable(): Observable<Optional<Float>> {
        val curMethod = object : Any() {}.javaClass.enclosingMethod
        return autoGetProcessor.getAutoGetSubject(
            curMethod,
            this::getVerticalDownSpeedLimitRx,
            2000
        ).distinctUntilChanged()
    }

    fun setConnectionFailSafeBehaviorRx(behavior: AircraftFailSafeBehaviorMode): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setConnectionFailSafeBehavior(
                behavior
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun getConnectionFailSafeBehaviorRx(): Single<AircraftFailSafeBehaviorMode> {
        return Single.create { emitter ->
            flyControllerManager?.getConnectionFailSafeBehavior(CallbackWithRxHandler(emitter))
        }
    }

    fun getConnectionFailSafeBehaviorObservable(): Observable<Optional<AircraftFailSafeBehaviorMode>> {
        val curMethod = object : Any() {}.javaClass.enclosingMethod
        return autoGetProcessor.getAutoGetSubject(curMethod, this::getConnectionFailSafeBehaviorRx, 2000)
            .distinctUntilChanged()
    }

    fun setHomeLocationUsingAircraftCurrentLocationRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setHomeLocationUsingAircraftCurrentLocation(CompletionCbRxHandler(emitter))
        }
    }

    fun setHomeLocationRx(latitude: Double, longitude: Double): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setHomeLocation(
                latitude, longitude
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun setPrecisionLandModeRx(mode: AircraftPrecisionLandMode): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setPrecisionLandModeEnable(
                mode
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun getPrecisionLandModeRx(): Single<AircraftPrecisionLandMode> {
        return Single.create { emitter ->
            flyControllerManager?.getPrecisionLandModeEnable(CallbackWithRxHandler(emitter))
        }
    }

    fun setLedEnableRx(enable: Boolean): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.setLedEnable(
                enable
            ) { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun getLedEnableRx(): Single<Boolean> {
        return Single.create { emitter ->
            flyControllerManager?.getLedEnable(CallbackWithRxHandler(emitter))
        }
    }

    fun rebootFCRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.rebootFC { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun startCalibrationCompassRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.startCalibrationCompass { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

    fun stopCalibrationCompassRx(): Completable {
        return Completable.create { emitter ->
            flyControllerManager?.stopCalibrationCompass { geoaiError ->
                handleError(emitter, geoaiError)
            }
        }
    }

}